﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System;

namespace Nox.Amuse.Controls
{

    public class BufferViewer : FlowDocumentScrollViewer
    {
        static BufferViewer()
        {
            // DefaultStyleKeyProperty.OverrideMetadata(typeof(BufferViewer), new FrameworkPropertyMetadata(typeof(BufferViewer)));
        }

        ///<summary>
        /// Gets or sets the scroll value. This is backed by a Dependency Property.
        ///</summary>
        public double ScrollValue
        {
            get { return (double)GetValue(ScrollValueProperty); }
            set { SetValue(ScrollValueProperty, value); }
        }
        ///<summary>This is the backing Dependency Property for the ScrollValue property.</summary>
        public static readonly DependencyProperty ScrollValueProperty = DependencyProperty.Register(
            "ScrollValue",
            typeof(double),
            typeof(BufferViewer),
            new UIPropertyMetadata(default(double), new PropertyChangedCallback(scrollValueChange)));
        /// <summary>
        /// Updates the ScrollValue Property when the value is set by a binding
        /// </summary>
        /// <param name="property">The property being changed</param>
        /// <param name="args">Data relating to the change</param>
        static void scrollValueChange(DependencyObject property, DependencyPropertyChangedEventArgs args)
        {
            BufferViewer bufferView = (BufferViewer)property;
            bufferView.ScrollViewer.ScrollToVerticalOffset((double)args.NewValue);
        }

        /// <summary>
        /// General Constructor
        /// </summary>
        public BufferViewer()
        {
            this.Loaded += new RoutedEventHandler(BufferViewer_Loaded);
        }

        /// <summary>
        /// Adds an event once the control has loaded all subparts
        /// </summary>
        /// <param name="sender">Object that sent the event</param>
        /// <param name="e">Arguments relating to the event</param>
        void BufferViewer_Loaded(object sender, RoutedEventArgs e)
        {
            this.ScrollViewer.ScrollChanged += new ScrollChangedEventHandler(ScrollViewer_ScrollChanged);
        }

        /// <summary>
        /// Called when the scroll viewer part has changed its position
        /// </summary>
        /// <param name="sender">Object that sent the event</param>
        /// <param name="e">Arguments relating to the event</param>
        void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.ExtentHeightChange == 0)
            {
                if (e.ViewportHeightChange == 0) // User or system is scrolling the box
                {
                    ScrollValue = ScrollViewer.VerticalOffset;
                    IsAtBottom = ScrollValue == ScrollViewer.ScrollableHeight ? true : false;
                }
                else // Box size has changed
                {
                    if (IsAtBottom.HasValue)
                    {
                        if (IsAtBottom.Value || ScrollValue > ScrollViewer.ScrollableHeight)
                        {
                            ScrollViewer.ScrollToBottom();
                            IsAtBottom = true;
                        }
                    }
                }
            }
            else
            {
                if (IsAtBottom.HasValue)
                {
                    if (IsAtBottom.Value)
                    {
                        ScrollViewer.ScrollToBottom();
                    }
                }
            }
        }

        public static readonly DependencyProperty IsAtBottomProperty =
            DependencyProperty.Register("IsAtBottom", typeof(bool?), typeof(BufferViewer), new UIPropertyMetadata(default(bool?)));

        public bool? IsAtBottom
        {
            get { return (bool?)GetValue(IsAtBottomProperty); }
            set { SetValue(IsAtBottomProperty, value); }
        }


        /// <summary> 
        /// Backing store for the ScrollViewer property. 
        /// </summary> 
        private ScrollViewer myScrollViewer;

        /// <summary> 
        /// Gets the scroll viewer contained within the FlowDocumentScrollViewer control 
        /// </summary> 
        public ScrollViewer ScrollViewer
        {
            get
            {
                if (this.myScrollViewer == null)
                {
                    DependencyObject obj = this;

                    do
                    {
                        if (VisualTreeHelper.GetChildrenCount(obj) > 0)
                            obj = VisualTreeHelper.GetChild(obj as Visual, 0);
                        else
                            return null;
                    }
                    while (!(obj is ScrollViewer));

                    this.myScrollViewer = obj as ScrollViewer;
                }

                return this.myScrollViewer;
            }

        }
    }
}
